/*
    Copyright (c) 2009 Pavol Malosek a.k.a. malo

    This file is part of ComComLib.

    ComComLib is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.

    ComComLib is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef __DEVICE_HPP_INCLUDED__
#define __DEVICE_HPP_INCLUDED__

#include <termios.h>
#include <unistd.h>
#include <string>
#include <list>

#include <lcc/device_info.hpp>
#include <lcc/command.hpp>
#include <lcc/dlmath.hpp>

namespace lcc
{
    //  UNIX timestamp in seconds.
    uint64_t time_now ();

    //  Prints out device_info structure.
    void print_device_info (device_info_t *device_info_);

    //  Prints record_t structure.
    void print_record (record_t &record_);

    //  Return logger codes structure.
    device_codes_t get_codes (int type_, int model_);

    //  Returns type of the input as a astring.
    const char *input_type_to_string (input_type_t input_type_);

    class device_t
    {
    public:
        device_t (void);
        virtual ~device_t (void) {};
        int open_tty (void);
        void close_tty (bool keep_tty_open_ = false);

        bool bogus_command (void);

        //  Open logger, issue bogus command and read logger response.
        virtual logger_command_status_t touch (void) = 0;

        //  Read logger system memmory.
        virtual logger_command_status_t read_service_memory (void) = 0; 

        //  Read and parse records.
        virtual logger_command_status_t read_records (void) = 0;

        //  Add records into the list, used by parser.
        void add_records (std::list <record_t> &records_); 
        
        //  Update device_inco obj. structure.
        bool update_device_info (void);

        //  Fills device_info structure.
        bool get_device_info (device_info_t *device_info_);

        //  Set parameters for online measuring.
        logger_command_status_t set_online_interval (size_t interval_);

        //  Get records from device.
        std::list<record_t> get_records (void);
    protected:
        //  Read logger data memmory.
        virtual logger_command_status_t 
            read_data_memory (uint16_t src_addr_, size_t size_, 
            bool keep_tty_open_ = false) = 0; 

        //  Read 256 bytes from src_ addr, note that address has be 
        //  aligned to 128B.
        ssize_t read_256_EE (void *dest_, uint16_t src_addr_);

        //  Read status word from logger 2B. 
        ssize_t read_status_word (void);

        char tty_name [256];

        //  Status word.
        uint16_t status_word;

        //  Service memory of the device.
        unsigned char *service_memory;

        //  Device info parsed from service memory.
        device_info_t device_info;        

        //  Data memory of the device.
        unsigned char *data_memory;

        //  List with measured values.
        std::list<record_t> records;

    private:

        //  Write data to tty and return response.
        ssize_t write_read_tty (const void *write_data_, size_t write_size_,
            void *read_buff_, size_t read_size_);

        ssize_t write_tty (const void *data_, size_t size_);
        ssize_t read_tty (void *buff_, size_t size_, unsigned int timeout_ = 1);

        //  Read logger memory.
        ssize_t read_EE (void *dest_, uint16_t src_addr_, size_t size_);

        //  Calculate checksum.
        inline uint8_t checksum_range (const void *beg_, size_t size_)
        {
            unsigned char *beg = (unsigned char*)beg_;
            int sum = 0;

            for (unsigned int i = 0; i < size_; i++) {
                sum += *(beg + i);
            }
            //  Return low byte from checksum. 
            return sum & 0xff;
        }

        //  File descriptor of the serial device.
        int tty_fd;

        //  poll interval, for online measuring
        int poll_interval;

        //  Next poll
        uint64_t next_poll;

        //  original port settings
        struct termios old_tio;
    };
}
#endif
